<?php

namespace App\Service\SiteLocation;

use App\Models\Kms\User\KmsUser;
use App\Models\Wanggui\CustomerDepartmentClueRecordModel;
use App\Models\Wanggui\CustomerDepartmentFollowUpRecordModel;
use App\Models\Wanggui\CustomerDepartmentKpPartyRecordModel;
use App\Models\Wanggui\CustomerDepartmentOperationLogModel;
use App\Models\Wanggui\CustomerDepartmentTaskModel;
use App\Service\BaseService;
use Carbon\Carbon;
use Illuminate\Support\Facades\Artisan;
use Illuminate\Support\Facades\DB;

class SiteTaskService extends BaseService
{
    public static function overview()
    {
        $queryResults = CustomerDepartmentTaskModel::query()
            ->selectRaw(
                '
            COUNT(*) AS total,
            SUM(CASE WHEN grade IN (?, ?, ?) THEN 1 ELSE 0 END) AS sab_mall,
            SUM(CASE WHEN settle = ? THEN 1 ELSE 0 END) AS unsettled,
            SUM(CASE WHEN manageStatus = 0 THEN 1 ELSE 0 END) AS unassigned,
            SUM(CASE WHEN manageStatus = 1 THEN 1 ELSE 0 END) AS assigned,
            SUM(CASE WHEN projectPhase = ? THEN 1 ELSE 0 END) AS effective_clue,
            SUM(CASE WHEN projectPhase = ? THEN 1 ELSE 0 END) AS effective_house,
            SUM(CASE WHEN projectPhase in (?, ?) THEN 1 ELSE 0 END) AS site_located
        ', [
                    CustomerDepartmentTaskModel::GRADE_S,
                    CustomerDepartmentTaskModel::GRADE_A,
                    CustomerDepartmentTaskModel::GRADE_B,
                    CustomerDepartmentTaskModel::SETTLE_STATUS_OFF,
                    CustomerDepartmentTaskModel::PROJECT_PHASE_EFFECTIVE_CLUE,
                    CustomerDepartmentTaskModel::PROJECT_PHASE_EFFECTIVE_HOUSE,
                    CustomerDepartmentTaskModel::PROJECT_PHASE_SITE_LOCATION,
                    CustomerDepartmentTaskModel::PROJECT_PHASE_SITE_CONFIRM
                ]
            )
            ->first();

        return [
            [
                'text'  => '商场网规',
                'count' => $queryResults->total ?: 0
            ],
            [
                'text'  => 'SAB商场',
                'count' => $queryResults->sab_mall ?: 0
            ],
            [
                'text'  => '未入驻',
                'count' => $queryResults->unsettled ?: 0
            ],
            [
                'text'  => '待指派',
                'count' => $queryResults->unassigned ?: 0
            ],
            [
                'text'  => '已指派',
                'count' => $queryResults->assigned ?: 0
            ],
            [
                'text'  => '有效线索',
                'count' => $queryResults->effective_clue ?: 0
            ],
            [
                'text'  => '有效房源',
                'count' => $queryResults->effective_house ?: 0
            ],
            [
                'text'  => '已确址',
                'count' => $queryResults->site_located ?: 0
            ],
        ];
    }


    /**
     * 任务列表
     * @param $pageNum
     * @param $pageSize
     * @param $rmsUserId
     * @param $provinceCode
     * @param $cityCode
     * @param $districtCode
     * @param $wgType
     * @param $wgName
     * @param $grade
     * @param $ranking
     * @param $settle
     * @param $manageStatus
     * @param $projectPhase
     * @param $assignId
     * @param $assignStartTime
     * @param $assignEndTime
     * @param $followUpStartTime
     * @param $followUpEndTime
     * @param $preHavingStartTime
     * @param $preHavingEndTime
     * @param $sortField
     * @param $sortOrder
     * @return array
     */
    public static function list($pageNum, $pageSize, $rmsUserId, $provinceCode, $cityCode, $districtCode, $wgType, $wgName, $grade, $ranking, $settle, $manageStatus, $projectPhase, $assignId, $assignStartTime, $assignEndTime, $followUpStartTime, $followUpEndTime, $preHavingStartTime, $preHavingEndTime, $sortField, $sortOrder): array
    {
        $paginator = CustomerDepartmentTaskModel::query()
            ->when($provinceCode, function ($query) use ($provinceCode) {
                $query->where('provinceCode', $provinceCode);
            })
            ->when($cityCode, function ($query) use ($cityCode) {
                $query->where('cityCode', $cityCode);
            })
            ->when($districtCode, function ($query) use ($districtCode) {
                $query->where('districtCode', $districtCode);
            })
            ->when(mb_strlen($wgType), function ($query) use ($wgType) {
                $query->where('wgType', $wgType);
            })
            ->when(mb_strlen($wgName), function ($query) use ($wgName) {
                $query->where('wgName', 'like', "%{$wgName}%");
            })
            ->when($grade, function ($query) use ($grade) {
                $gradeArr = explode(',', $grade);
                $query->whereIn('grade', $gradeArr);
            })
            ->when(mb_strlen($settle), function ($query) use ($settle) {
                $settleArr = explode(',', $settle);
                $query->whereIn('settle', $settleArr);
            })
            ->when(mb_strlen($manageStatus), function ($query) use ($manageStatus) {
                $manageStatusArr = explode(',', $manageStatus);
                $query->whereIn('manageStatus', $manageStatusArr);
            })
            ->when(mb_strlen($projectPhase), function ($query) use ($projectPhase) {
                $projectPhaseArr = explode(',', $projectPhase);
                $query->whereIn('projectPhase', $projectPhaseArr);
            })
            ->when($assignId, function ($query) use ($assignId) {
                $query->where('assignId', $assignId)
                    ->orderByRaw("CASE WHEN preHaving = 0 THEN 1 ELSE 0 END ASC")
                    ->orderBy('preHaving', 'ASC');
            })
            ->when($ranking, function ($query) use ($ranking) {
                $query->where('ranking', $ranking);
            })
            ->when(mb_strlen($assignStartTime) && mb_strlen($assignEndTime), function ($query) use ($assignStartTime, $assignEndTime) {
                $query->whereBetween("assignTime", [Carbon::createFromDate($assignStartTime)->timestamp, Carbon::createFromDate($assignEndTime)->endOfDay()->timestamp]);
            })
            ->when(mb_strlen($sortOrder), function ($query) use ($sortOrder, $sortField) {
                $orderMethod = $sortOrder === 'ascend' ? 'orderBy' : 'orderByDesc';
                switch ($sortField) {
                    case 'grade':
                    case 'ranking':
                    case 'assignTime':
                    case 'followUpTime':
                    case 'preHaving':
                        $query->$orderMethod($sortField);
                        break;
                    default:
                }
            })
            ->when(!mb_strlen($sortOrder), function ($query) {
                $query->orderByDesc('assignTime');
            })
            ->when(mb_strlen($followUpStartTime) && mb_strlen($followUpEndTime), function ($query) use ($followUpStartTime, $followUpEndTime) {
                $startTime = Carbon::createFromDate($followUpStartTime)->timestamp;
                $endTime   = Carbon::createFromDate($followUpEndTime)->endOfDay()->timestamp;
                $query->whereRaw("id in (select taskId from customer_department_follow_up_record where createdAt between {$startTime} and {$endTime})");
            })
            ->when(mb_strlen($preHavingStartTime) && mb_strlen($preHavingEndTime), function ($query) use ($preHavingStartTime, $preHavingEndTime) {
                $startTime = Carbon::createFromDate($preHavingStartTime)->timestamp;
                $endTime   = Carbon::createFromDate($preHavingEndTime)->endOfDay()->timestamp;
                $query->whereRaw("id in (select taskId from customer_department_clue_record where preHaving between {$startTime} and {$endTime})");
            })
            ->with(['clueRel', 'followUpRel'])
            ->paginate($pageSize, ['*'], 'pageNum', $pageNum);

        $userIds   = array_merge($paginator->pluck('assignId')->toArray(), $paginator->pluck('updatedByUid')->toArray());
        $userInfos = [];
        KmsUser::query()
            ->whereIn('rmsUserId', $userIds)
            ->get()
            ->each(function (KmsUser $kmsUser) use (&$userInfos) {
                if ($kmsUser->rmsUserId != 0) {
                    $userInfos[$kmsUser->rmsUserId] = $kmsUser->nickname . '(' . $kmsUser->name . ')';
                }
            });

        $list = $paginator->map(function ($item) use ($userInfos) {

            // 最新线索内容
            $clueContent = '';
            if (count($item->clueRel)) {
                $clueContent = $item->clueRel->last()->content;
            }

            return [
                'id'                => $item->id,
                'wgName'            => $item->wgName,
                'grade'             => $item->grade,
                'ranking'           => $item->ranking ?: '',
                'gradeStr'          => CustomerDepartmentTaskModel::GRADE_MAPPING[$item->grade] ?? '-',
                'prefixAddress'     => $item->prefixAddress,
                'settle'            => $item->settle,
                'settleStr'         => CustomerDepartmentTaskModel::SETTLE_STATUS_MAPPING[$item->settle] ?? '未入驻',
                'manageStatus'      => $item->manageStatus,
                'manageStatusStr'   => CustomerDepartmentTaskModel::MANAGE_STATUS_MAPPING[$item->manageStatus] ?? '未指派',
                'projectPhase'      => $item->projectPhase,
                'projectPhaseStr'   => CustomerDepartmentTaskModel::PROJECT_PHASE_MAPPING[$item->projectPhase] ?? '-',
                'departmentManager' => $userInfos[$item->assignId] ?? '',
                'assignTime'        => $item->assignTime ? Carbon::createFromTimestamp($item->assignTime)->toDateTimeString() : '-',
                'clueContent'       => $clueContent,
                'preHaving'         => $item->preHaving ? Carbon::createFromTimestamp($item->preHaving)->toDateString() : '-',
                'followUpTime'      => $item->followUpTime ? Carbon::createFromTimestamp($item->followUpTime)->toDateTimeString() : '-',
                'updatedAt'         => $item->updatedAt->toDateTimeString(),
                'updatedByUser'     => $userInfos[$item->updatedByUid] ?? '',
            ];
        });

        return [
            'count'    => $paginator->total(),
            'list'     => $list,
            'pageNum'  => $pageNum,
            'pageSize' => $pageSize,
        ];
    }


    /**
     * 任务详情
     * @param int $id
     * @param int $rmsUserId
     * @return array
     */
    public static function detail(int $id, int $rmsUserId): array
    {
        $taskModel = CustomerDepartmentTaskModel::query()
            ->where('id', $id)
            ->with([
                'clueRel',
                'followUpRel' => function ($query) {
                    $query->with(['resourceRel', 'kpPartyRel']);
                },
                'kpPartyRel'
            ])
            ->first();

        if (null == $taskModel) {
            self::throwErr('任务不存在', 404);
        }

        $userIds   = array_merge([$taskModel->assignId, $taskModel->createdByUid, $taskModel->updatedByUid], $taskModel->clueRel->pluck('createdByUid')->toArray());
        $userInfos = [];
        KmsUser::query()
            ->whereIn('rmsUserId', $userIds)
            ->get()
            ->each(function (KmsUser $kmsUser) use (&$userInfos) {
                if ($kmsUser->rmsUserId != 0) {
                    $userInfos[$kmsUser->rmsUserId] = $kmsUser->nickname . '(' . $kmsUser->name . ')';
                }
            });

        // 线索记录
        $clueRecord = [];
        if (count($taskModel->clueRel)) {
            foreach ($taskModel->clueRel as $clueRel) {
                $clueRecord[] = [
                    'proHaving' => Carbon::createFromTimestamp($clueRel->preHaving)->toDateString(),
                    'username'  => $userInfos[$clueRel->createdByUid] ?? '',
                    'time'      => $clueRel->createdAt->toDateTimeString(),
                    'status'    => $clueRel->status,
                    'statusStr' => CustomerDepartmentClueRecordModel::STATUS_MAPPING[$clueRel->status] ?? '',
                ];
            }
        }

        // 客户信息
        $kpPartyRecord = [];

        //跟进记录
        $followUpRecord   = [];
        $followUpLastTime = '-';
        if (count($taskModel->followUpRel)) {
            $followUpLastTime = $taskModel->followUpRel->last()->createdAt->toDateTimeString();
            foreach ($taskModel->followUpRel as $followUpRel) {
                $files = [];
                if (count($followUpRel->resourceRel)) {
                    $files = collect($followUpRel->resourceRel)->map(function ($file) {
                        return picturePath($file['url']);
                    });
                }
                $followUpRecord[] = [
                    'type'        => $followUpRel->type,
                    'typeStr'     => CustomerDepartmentFollowUpRecordModel::TYPE_MAPPING[$followUpRel->type] ?? '',
                    'method'      => $followUpRel->method,
                    'methodStr'   => CustomerDepartmentFollowUpRecordModel::METHOD_MAPPING[$followUpRel->method] ?? '',
                    'content'     => $followUpRel->content,
                    'time'        => $followUpRel->createdAt->toDateTimeString(),
                    'files'       => $files,
                    'createdTime' => $followUpRel->createdAt->timestamp,
                ];

                if (null != $followUpRel->kpPartyRel) {
                    $kpPartyRecord[] = [
                        'name'          => $followUpRel->kpPartyRel->name,
                        'gender'        => $followUpRel->kpPartyRel->gender,
                        'genderStr'     => CustomerDepartmentKpPartyRecordModel::GENDER_MAPPING[$followUpRel->kpPartyRel->gender] ?? '',
                        'position'      => $followUpRel->kpPartyRel->position,
                        'company'       => $followUpRel->kpPartyRel->company ?: '-',
                        'phone'         => $followUpRel->kpPartyRel->phone,
                        'prefixAddress' => $followUpRel->kpPartyRel->prefixAddress,
                        'existProject'  => 'A,B,C',
                        'wechatCode'    => $followUpRel->kpPartyRel->wechatCode,
                        'onTheJob'      => $followUpRel->kpPartyRel->onTheJob,
                        'onTheJobStr'   => CustomerDepartmentKpPartyRecordModel::IS_ON_THE_JOB_MAPPING[$followUpRel->kpPartyRel->onTheJob] ?? '',
                        'createdAt'     => $followUpRel->kpPartyRel->createdAt->toDateTimeString(),
                    ];
                }
            }
        }

        $operationLog = [];
        $logModel     = CustomerDepartmentOperationLogModel::query()
            ->where('taskId', $taskModel->id)
            ->orderByDesc('createdAt')
            ->with(['userRel'])
            ->get();

        if (null != $logModel) {
            $logModel->each(function (CustomerDepartmentOperationLogModel $customerDepartmentOperationLogModel) use (&$operationLog) {
                $username = '';
                if (null != $customerDepartmentOperationLogModel->userRel) {
                    $username = $customerDepartmentOperationLogModel->userRel->nickname . '(' . $customerDepartmentOperationLogModel->userRel->name . ')';
                }
                $operationLog[] = [
                    'username' => $username,
                    'desc'     => $customerDepartmentOperationLogModel->content,
                    'time'     => $customerDepartmentOperationLogModel->createdAt->toDateTimeString(),
                    'changes'  => $customerDepartmentOperationLogModel->changes ? json_decode($customerDepartmentOperationLogModel->changes, true) : []
                ];
            });
        }


        return [
            'id'                => $taskModel->id,
            'wgName'            => $taskModel->wgName,
            'grade'             => $taskModel->grade,
            'ranking'           => $taskModel->ranking ?: '',
            'gradeStr'          => CustomerDepartmentTaskModel::GRADE_MAPPING[$taskModel->grade] ?? '-',
            'prefixAddress'     => $taskModel->prefixAddress,
            'settle'            => $taskModel->settle,
            'settleStr'         => CustomerDepartmentTaskModel::SETTLE_STATUS_MAPPING[$taskModel->settle] ?? '未入驻',
            'manageStatus'      => $taskModel->manageStatus,
            'manageStatusStr'   => CustomerDepartmentTaskModel::MANAGE_STATUS_MAPPING[$taskModel->manageStatus] ?? '未指派',
            'projectPhase'      => $taskModel->projectPhase,
            'projectPhaseStr'   => CustomerDepartmentTaskModel::PROJECT_PHASE_MAPPING[$taskModel->projectPhase] ?? '待跟进',
            'departmentManager' => $userInfos[$taskModel->assignId] ?? '',
            'followUpLastTime'  => $followUpLastTime,
            'followUpRecord'    => collect($followUpRecord)->sortByDesc('createdTime')->values()->toArray(),
            'clueRecord'        => $clueRecord,
            'kpPartyRecord'     => $kpPartyRecord,
            'operationLog'      => $operationLog,
            'updatedAt'         => $taskModel->updatedAt->toDateTimeString(),
            'updatedByUser'     => $userInfos[$taskModel->updatedByUid] ?? '',
        ];
    }


    /**
     * 指派开发经理
     * @param array $taskIdArr
     * @param int $userId
     * @param int $rmsUserId
     * @return int
     */
    public static function assign(array $taskIdArr, int $userId, int $rmsUserId): int
    {

        $taskModel = CustomerDepartmentTaskModel::query()
            ->whereIn('id', $taskIdArr);


        $userIds = $taskModel->pluck('assignId')->toArray();

        $userInfos = [];
        KmsUser::query()
            ->whereIn('rmsUserId', array_values(array_merge($userIds, [$userId])))
            ->get()
            ->each(function (KmsUser $kmsUser) use (&$userInfos) {
                if ($kmsUser->rmsUserId != 0) {
                    $userInfos[$kmsUser->rmsUserId] = $kmsUser->nickname . '(' . $kmsUser->name . ')';
                }
            });

        //已经指派的开发经理
        $oldAssignIdArr = (clone $taskModel)->pluck('assignId', 'id')->unique()->toArray();

        if ((clone $taskModel)->where('settle', CustomerDepartmentTaskModel::SETTLE_STATUS_OK)->exists()) {
            self::throwErr('不能选择已入驻的项目，请重新选择', 403);
        }

        if (!$userId) {
            (clone $taskModel)->update([
                'assignId'     => 0,
                'assignTime'   => 0,
                'manageStatus' => CustomerDepartmentTaskModel::MANAGE_STATUS_WAIT_ASSIGN,
                'updatedByUid' => $rmsUserId
            ]);

            $userIds = implode(',', array_values($oldAssignIdArr));
            Artisan::call("siteLocation:sync-development-manager-task-info --rmsUserIds={$userIds}");


            // 添加日志
            foreach ($taskIdArr as $taskId) {
                CustomerDepartmentOperationLogModel::addLog($taskId, '取消指派开发经理', [
                    [
                        'theme' => '取消指派开发经理',
                        'data'  => [
                            [
                                'key'         => 'assignId',
                                'beforeValue' => $userInfos[$oldAssignIdArr[$taskId] ?? 0] ?? '-',
                                'afterValue'  => '-',
                                'beforeText'  => $userInfos[$oldAssignIdArr[$taskId] ?? 0] ?? '-',
                                'afterText'   => '-',
                                'type'        => 1,
                                'description' => '开发经理',
                            ]
                        ]
                    ]
                ], $rmsUserId);
            }

            return true;
        }

        // 判断任务状态
        $taskManageStatus = (clone $taskModel)
            ->pluck('manageStatus', 'id')
            ->toArray();

        $noAssignTaskIds = [];
        $assignTaskIds   = [];
        foreach ($taskManageStatus as $key => $manageStatus) {
            if ($manageStatus == 0) {
                $noAssignTaskIds[] = $key;
            } else {
                $assignTaskIds[] = $key;
            }
        }

        (clone $taskModel)->whereIn('id', $noAssignTaskIds)
            ->update([
                'assignId'     => $userId,
                'assignTime'   => time(),
                'manageStatus' => CustomerDepartmentTaskModel::MANAGE_STATUS_ASSIGN,
                'projectPhase' => CustomerDepartmentTaskModel::PROJECT_PHASE_WAIT_FOLLOW_UP,
                'updatedByUid' => $rmsUserId
            ]);

        (clone $taskModel)->whereIn('id', $assignTaskIds)
            ->update([
                'assignId'     => $userId,
                'assignTime'   => time(),
                'updatedByUid' => $rmsUserId
            ]);

        $userIds = implode(',', array_unique(array_merge([$userId], array_values($oldAssignIdArr))));

        Artisan::call("siteLocation:sync-development-manager-task-info --rmsUserIds={$userIds}");

        // 添加日志
        foreach ($noAssignTaskIds as $taskId) {
            CustomerDepartmentOperationLogModel::addLog($taskId, '指派开发经理', [
                [
                    'theme' => '指派开发经理',
                    'data'  => [
                        [
                            'key'         => 'assignId',
                            'beforeValue' => '',
                            'afterValue'  => $userInfos[$userId] ?? '-',
                            'beforeText'  => '',
                            'afterText'   => $userInfos[$userId] ?? '-',
                            'type'        => 1,
                            'description' => '开发经理',
                        ]
                    ]
                ]
            ], $rmsUserId);
        }

        foreach ($assignTaskIds as $taskId) {
            CustomerDepartmentOperationLogModel::addLog($taskId, '修改指派开发经理', [
                [
                    'theme' => '修改指派开发经理',
                    'data'  => [
                        [
                            'key'         => 'assignId',
                            'beforeValue' => $userInfos[$oldAssignIdArr[$taskId] ?? 0] ?? '-',
                            'afterValue'  => $userInfos[$userId] ?? '-',
                            'beforeText'  => $userInfos[$oldAssignIdArr[$taskId] ?? 0] ?? '-',
                            'afterText'   => $userInfos[$userId] ?? '-',
                            'type'        => 1,
                            'description' => '开发经理',
                        ]
                    ]
                ]
            ], $rmsUserId);
        }

        return true;
    }

}
